home *** CD-ROM | disk | FTP | other *** search
- static char rcsid[] = "$Id: canonize.c,v 1.3 1992/11/10 03:14:34 mike Exp $";
-
- /* $Log: canonize.c,v $
- * Revision 1.3 1992/11/10 03:14:34 mike
- * - `canonize' now works for path names, too.
- *
- * Revision 1.2 1992/09/07 00:33:52 mike
- * - Rewrote `canonize' completely for the ATARI version.
- *
- * Revision 1.1 1992/09/06 19:31:32 mike
- * Initial revision
- *
- */
-
- /*
- * Name: canonize
- * Purpose:
- * Calculate a file's unique (canonical) pathname, suitable for comparing
- * with other canonical names.
- * Usage: char *canonize(fname,cname, curdir);
- * Input:
- * char *fname; Pointer to file name to canonize.
- * char *cname; Where to put the canonical name.
- * char *curdir; Pointer to the name of the current directory. Pass in
- * (char *)NULL if you want me to query the OS for this
- * info (the normal case).
- * Returns:
- * Pointer to canonical name, or NULL if file name was illegal.
- * Notes:
- * On Unix, getcwd() is VERY slow. If you call canonize() very often,
- * you'll want to call getcwd() once, save the dir and pass it in via
- * curdir.
- * No wildcards in fname - see fxpand().
- * MS-DOS
- * "A:" => "A:<current directory>"
- * The canonical name will only contain "/"s. No "\"s.
- * Will parse both "\" and "/".
- * The drive letter is uppercase, everything else is lowercase.
- * ATARIST (from jwahar r. bammi (bammi@cadence.com))
- * Usage just like Unix. The library getcwd will canonize, and will be
- * consistent (especially) inspite of unixmode. Also getcwd() is not
- * expensive on the atari, so we use it.
- * Every file has exactly one, unique canonical name. Canonical names may
- * be compared to determine if two names specify the same file.
- * The format for canonical names is: C:/path/FILE.EXT or C:/path/FILE
- * for files lacking an extension. Note that the drive name is
- * always included, a complete path name (starting at the root) is
- * provided and references to "." and ".." are removed.
- * Leading blanks in file name are ignored and dropped from the
- * canonical name.
- * On Domain/OS (Apollo), 2 leading slashes (//foo) is very different
- * from a single leading slash. Yech. "Normal" Unix doesn't care if
- * there is one or more leading slashes. Also, "//foo/.." => "//".
- * "/.." => "//" but I don't know if I care enough to make this
- * work.
- * Defects:
- * Character device names are not recognized, and so they are treated
- * like ordinary files.
- * Error checking is not very robust.
- * WARNING
- * This routine is a classic bomb waiting to go off. It fills a fixed
- * length string (of unknown length) with text of unknown lengths. One
- * of these days it will write off the end.
- * Also, the routine getcwd() is used poorly. I should do getter error
- * checking and give it a better chance of working with a long path name.
- * The real fix for this is to use dynamic strings. Until then, pass in a
- * big buffer.
- * System:
- * MS-DOS 2.1 and up. Lattice C
- * With minor mods: Microsoft C
- * Unix
- * Domain/OS (mostly)
- * Author: Jim Conrad 06/08/86
- * Rewritten: Craig Durland 9/86, 6/89
- * Modified: 11/91
- */
-
- /* Copyright 1986 Craig Durland
- * Distributed under the terms of the GNU General Public License.
- * Distributed "as is", without warranties of any kind, but comments,
- * suggestions and bug reports are welcome.
- */
-
- #include <stdio.h>
- #include <os.h>
- #include <const.h>
- #include <char.h> /* <char.h> or <ctype.h> */
-
- extern char *getcwd();
-
- static char *fnptr, *cnptr; /* !!! not reentrent */
- static int get_dpart();
-
- /* flags for get_dpart() */
- #define TEXT 0
- #define PARENT 1
- #define DONE 2
- #define ZILCH 3
-
-
- #ifdef ATARI
-
- /*
- * Strip off the last dir name of a path.
- * `p' points to the byte after the last valid
- * char in the path, not the slash.
- */
-
-
- static char *strip_last_dir(p,cname)
- register char *p;
- register char *cname;
- {
- while (--p >= cname)
- if (*p == U_SLASH)
- return p + 1;
- return NULL;
- }
-
-
-
- char *canonize(fname,cname,curdir)
- char *fname;
- char *cname;
- char *curdir;
- {
- register char *cp;
- register char *fp;
- int prefix;
-
- cp = cname;
- fp = fname;
- /*
- * See if `fname' contains a path prefix.
- */
- prefix = 0;
- if (fp[0] == M_SLASH || fp[0] == U_SLASH)
- {
- if (tolower(fp[1]) == 'd' && tolower(fp[2]) == 'e' && tolower(fp[3]) == 'v'
- && (fp[4] == M_SLASH || fp[4] == U_SLASH) && isalpha(fp[5])
- && (fp[6] == M_SLASH || fp[6] == U_SLASH))
- prefix = 1;
- else
- prefix = 2;
- }
- else if (fp[1] == ':')
- prefix = 3;
- else if (fp[0] == '.')
- {
- if (fp[1] == M_SLASH || fp[1] == U_SLASH || fp[1] == '\0')
- prefix = 4;
- else if (fp[1] == '.' && (fp[2] == M_SLASH || fp[2] == U_SLASH || fp[2] == '\0'))
- prefix = 5;
- }
- switch (prefix)
- {
- case 0 :
- /*
- * No path prefix.
- */
- if (curdir == NULL)
- {
- if (getcwd(cp,250) == NULL)
- return NULL;
- }
- else
- strcpy(cp,curdir);
- while (*cp++);
- --cp;
- if (cp[-1] != U_SLASH)
- *cp++ = U_SLASH;
- strcpy(cp,fp);
- return cname;
- case 1 :
- /*
- * A path of the form /dev/x....
- */
- *cp++ = tolower(fp[5]);
- *cp++ = ':';
- *cp++ = U_SLASH;
- fp += 7;
- break;
- case 2 :
- /*
- * A path starting with a slash.
- */
- if (curdir == NULL)
- {
- if (getcwd(cp,250) == NULL)
- return NULL;
- }
- else
- strcpy(cp,curdir);
- cp += 3;
- fp++;
- break;
- case 3 :
- /*
- * A path starting with a drive id and a colon.
- */
- *cp++ = tolower(*fp++);
- *cp++ = *fp++;
- *cp++ = U_SLASH;
- fp++;
- break;
- case 4 :
- /*
- * A path starting with a dot.
- */
- if (curdir == NULL)
- {
- if (getcwd(cp,250) == NULL)
- return NULL;
- }
- else
- strcpy(cp,curdir);
- while (*cp++);
- --cp;
- if (fp[1] == M_SLASH || fp[1] == U_SLASH)
- {
- *cp++ = U_SLASH;
- fp += 2;
- }
- else
- fp++;
- break;
- case 5 :
- /*
- * A path starting with two dots.
- */
- if (curdir == NULL)
- {
- if (getcwd(cp,250) == NULL)
- return NULL;
- }
- else
- strcpy(cp,curdir);
- while (*cp++);
- --cp;
- if ((cp = strip_last_dir(cp,cname)) == NULL)
- return NULL;
- if (fp[2] == M_SLASH || fp[2] == U_SLASH)
- fp += 3;
- else
- fp += 2;
- }
- /*
- * At this point we got the drive id, the colon and the
- * slash, `fp' points to the first directory in the remaining
- * path or to the filename.
- */
- while (*fp)
- {
- switch (*fp)
- {
- case M_SLASH :
- case U_SLASH :
- *cp++ = U_SLASH;
- if (*fp++ == '.')
- {
- if (fp[1] = '.' && (fp[2] == M_SLASH || fp[2] == U_SLASH))
- {
- if ((cp = strip_last_dir(cp - 1, cname)) == NULL)
- return NULL;
- fp += 3;
- }
- else if (fp[1] == M_SLASH || fp[1] == U_SLASH)
- fp += 2;
- }
- break;
- default :
- *cp++ = tolower(*fp++);
- }
- }
- *cp = '\0';
- if (cp == cname)
- return NULL;
- return cname;
- }
-
- #else
-
- /* convert fname to a full file spec */
- char *canonize(fname,cname, curdir) char *fname; char *cname, *curdir;
- {
- register char *first_slash;
-
- fnptr = fname; cnptr = cname;
-
- while (isspace(*fnptr)) fnptr++; /* Ignore leading white space */
-
- /* Ensure file name is not empty ie contains at least "c\0" */
- if (*fnptr == '\0') return NULL;
-
- #if MSDOZ
- if (fnptr[1] == ':') /* if drive provided, use it */
- { *cnptr++ = toupper(*fnptr); fnptr += 2; }
- else *cnptr++ = 'A' +getdsk(); /* drive missing: use current drive */
- *cnptr++ = ':';
- #endif /* MSDOZ */
-
- first_slash = cnptr; /* point to opening slash */
- if (ISSLASH(*fnptr))
- {
- *cnptr++ = U_SLASH;
- #if DOMAIN_OS /* just for Domain/OS. Yech */
- {
- char c;
- /* Check to see if fname starts with // (and only //) */
- if (ISSLASH(fnptr[1]))
- if ((c = fnptr[2]) == '\0' || !ISSLASH(c))
- { fnptr++; *cnptr++ = U_SLASH; first_slash++; }
- }
- #endif /* DOMAIN_OS */
- }
- else /* No leading "/" => path name not anchored */
- { /* so fname is relative to current directory */
- #if MSDOZ
- *cnptr++ = U_SLASH; /* tack on a leading slash */
- if (getcd(*cname -'A' +1,cnptr)) return NULL;
- if (*cnptr) /* if current dir != "" (ie the root) */
- { /* skip over dir, switching slashes as we go along */
- for (; *cnptr; cnptr++) if (*cnptr == M_SLASH) *cnptr = U_SLASH;
- *cnptr++ = U_SLASH;
- }
- #else
-
- #if UX_OS
- if (curdir) strcpy(cnptr,curdir); /* better be canonized */
- else if (getcwd(cnptr,250) == NULL) return NULL; /* at least a "/" */
- while (*cnptr) cnptr++; /* move to end of current directory */
- if (cnptr[-1] != U_SLASH) *cnptr++ = U_SLASH; /* in case cd is "/" */
- #else
-
- #if ATARI
- if (getcwd(cnptr,250) == NULL) return NULL; /* at least a "/" */
- #if defined(__MINT__) /* just in case */
- for (; *cnptr; cnptr++) if (*cnptr == M_SLASH) *cnptr = U_SLASH;
- #else
- while (*cnptr) cnptr++; /* move to end of current directory */
- #endif /* __MINT__ */
- if (cnptr[-1] != U_SLASH) *cnptr++ = U_SLASH; /* in case cd is "/" */
- #else
-
- /* Nothing defined, nuke the compile */
- Need_to_define = Something;
- #endif /* ATARI */
- #endif /* UX_OS */
- #endif /* MSDOZ */
- }
-
- while (TRUE)
- {
- switch (get_dpart())
- {
- case DONE: *cnptr = '\0'; goto done;
- case PARENT:
- if (--cnptr != first_slash) while (*--cnptr != U_SLASH) ;
- /* now tack on a slash after the name */
- case TEXT: *cnptr++ = U_SLASH; break;
- }
- }
- done:
- if (--cnptr != first_slash) *cnptr = '\0'; /* get rid of trailing slash */
-
- #if MSDOZ
- lowercase(first_slash); /* lowercase all but drive */
- #endif /* MSDOZ */
- return cname;
- }
-
- /* know: cnptr[-1] == slash */
- static int get_dpart()
- {
- register char *ptr = cnptr;
- register char c1, c2;
-
- if (*fnptr == '.') /* check for /. or /.. */
- {
- fnptr++; /* point to "/", "." or "" */
- c1 = fnptr[0];
- if (!(ISSLASH(c1) || c1 == '\0')) /* ignore "/./" or "/." */
- {
- c2 = fnptr[1];
- if (c1 == '.' && (ISSLASH(c2) || c2 == '\0')) /* "/../" or "/.." */
- { fnptr++; return PARENT; }
- *cnptr++ = '.'; /* false alarm */
- }
- }
- while (*fnptr)
- {
- if (ISSLASH(*fnptr)) { fnptr++; break; }
- *cnptr++ = *fnptr++;
- }
- if (cnptr != ptr) return TEXT;
- if (*fnptr == '\0') return DONE;
- return ZILCH; /* probably something like multiple slashes */
- }
-
- #endif /* ATARI */
-
-
-
- #ifdef TEST
- /* ******************************************************************** */
- /* *************** Test *********************************************** */
- /* ******************************************************************** */
-
- main()
- {
- char buf[80], cname[512];
-
- printf("File name to canonize: "); gets(buf);
- if (NULL == canonize(buf,cname, (char *)NULL)) printf("Bleech\n");
- else printf(">%s<\n>%s<\n",buf,cname);
- }
- #endif
-